import pprint
import logging
import yaml

logger = logging.getLogger(__name__)

#
# TODO: Need to finish this ...
#

class InvalidConfigException(Exception):
    def __init__(self, filename, reason):
        message = 'Unable to parse config file "%s": %s' % (filename, reason)
        super(InvalidConfigException, self).__init__(message)

class Config(object):
    '''Parses config files and maintains the resulting objects.'''

    def __init__(self):
        self._reset()
        
    def _reset(self):
        self._services = {}
        self._hosts = {}
        self._environments = {}
        
    def read(self, filename):
        '''Read config settings from the specified file.''' 
        self._reset()
        
        try:
            configFile = open(filename)
            
            for section in yaml.load_all(configFile): #@UndefinedVariable
                if 'config' not in section:
                    logger.warning('Section does not have "config" key: %s' % pprint.pformat(section))
                    continue
                
                sectionClass = Config.Section.getSectionClass(section)
                sectionInstance = sectionClass(**section)
                
                self._addSection(sectionInstance)
            
        except Exception:
            logger.exception('Unexpected exception while parsing config file: %s' % filename)
    
    def _addSection(self, section):
        if isinstance(section, Config.Service):
            self._addSectionToGroup(section, self._services)
        elif isinstance(section, Config.Host):
            self._addSectionToGroup(section, self._hosts)
        elif isinstance(section, Config.Environment):
            self._addSectionToGroup(section, self._environments)
        else:
            raise Exception('Unrecognized section type: %s' % section.__class__.__name__)
                
    def _addSectionToGroup(self, section, group):
        if section.name in group:
            logger.warning('Cowardly refusing to add conflicting section "%s"' % section.name)
        else:
            group[section.name] = section
            
    
    class Section(object):
        
        def __init__(self, **kwargs):
            self.configType = kwargs['config']
            self.name = kwargs['name']
            
            if self.__class__.__name__.lower() != self.configType.lower():
                raise AssertionError('Config type "%s" does not match class name "%s"' % 
                                        (self.configType, self.__class__.__name__))
        
        @classmethod
        def getSectionClass(cls, section):
            sectionTypes = {
                'service' : Config.Service,
                'environment' : Config.Environment,
                'host' : Config.Host,                    
            }
            
            return sectionTypes[section.get('config')]
        
    class Service(Section):
        def __init__(self, **kwargs):
            super(Config.Service, self).__init__(**kwargs)
            
            self.type = kwargs['type']
            self.displayName = kwargs['displayName']
            self.shortName = kwargs['shortName']
    
    class Environment(Section):
        def __init__(self, **kwargs):
            super(Config.Environment, self).__init__(**kwargs)
            
            self.hosts = kwargs['hosts']
    
    class Host(Section):
        def __init__(self, **kwargs):
            super(Config.Host, self).__init__(**kwargs)
            
            self.address = kwargs['address']
            self.services = kwargs['services']